#include "Vector.h"

Vector::Vector(size_t s)
{
    this->_dim = s;
    this->_vec = vector<long double>(s);
}

Vector::Vector(long double a, long double b)
{
    this->_dim = 2;
    this->_vec = vector<long double>({ a,b });
}

Vector::Vector(long double a, long double b, long double c)
{
    this->_dim = 3;
    this->_vec = vector<long double>({ a,b,c });
}

Vector::Vector(size_t s, std::vector<long double>vec)
{
    this->_dim = s;
    if (vec.size() != s)
    {
        throw"size error";
        return;
    }
    this->_vec = vec;
}

Vector::Vector(size_t s, const long double* vec)
{
    this->_dim = s;
    this->_vec = vector<long double>(s);
    for (size_t i = 0; i < s; i++)
    {
        this->_vec[i] = vec[i];
    }
}

Vector::Vector(const Vector& Vec)
{
    this->_dim = Vec._dim;
    this->_vec = Vec._vec;
}


size_t Vector::dim() const
{
    return size_t(this->_dim);
}

long double Vector::mag()
{
    long double a = 0;
    for (int i = 0; i < this->_dim; i++)
    {
        a = a + this->_vec[i] * this->_vec[i];
    }
    return sqrt(a);
}


long double& Vector::operator[](size_t i)
{
    if (i >= this->_dim)
    {
        throw"invalid Vector subscript";
    }
    return this->_vec[i];
}


long double& Vector::at(size_t i)
{
    if (i >= this->_dim)
    {
        throw"invalid Vector subscript";
    }
    return this->_vec[i];
}


Matrix RowVec(Vector Vec)
{
    Matrix Mat(1, Vec.dim());
    for (int i = 0; i < Vec.dim(); i++)
    {
        Mat.at(0, i) = Vec[i];
    }
    return Mat;
}


Matrix ColVec(Vector Vec)
{
    Matrix Mat(Vec.dim(), 1);
    for (int i = 0; i < Vec.dim(); i++)
    {
        Mat.at(i, 0) = Vec[i];
    }
    return Mat;
}

long double operator* (Vector a, Vector b)
{
    if (a.dim() != b.dim())
    {
        throw"Illegal Vector Mul Operation";
        return 0;
    }
    Matrix MatAns = RowVec(a) * ColVec(b);
    return MatAns.at(0, 0);
}

long double VecAng(Vector a, Vector b)
{
    return (a * b) / (a.mag() * b.mag());
}

Vector operator+ (Vector a, Vector b)
{
    if (a.dim() != b.dim())
    {
        throw"Illegal Vector Plus Operation";
        return 0;
    }
    Vector VecAns(a.dim());
    for (int i = 0; i < a.dim(); i++)
        VecAns[i] = a[i] + b[i];
    return VecAns;
}
Vector operator- (Vector a)
{
    Vector VecAns(a.dim());
    for (int i = 0; i < a.dim(); i++)
        VecAns[i] = -a[i];
    return VecAns;
}
Vector operator- (Vector a, Vector b)
{
    if (a.dim() != b.dim())
    {
        throw"Illegal Vector Minus Operation";
        return 0;
    }
    Vector VecAns(a.dim());
    for (int i = 0; i < a.dim(); i++)
        VecAns[i] = a[i] - b[i];
    return VecAns;
}
Vector operator* (double a, Vector b)
{
    Vector VecAns(b.dim());
    for (int i = 0; i < b.dim(); i++)
        VecAns[i] = a * b[i];
    return VecAns;
}
Vector operator* (Vector b, double a)
{
    Vector VecAns(b.dim());
    for (int i = 0; i < b.dim(); i++)
        VecAns[i] = a * b[i];
    return VecAns;
}
Vector operator/ (Vector b, double a)
{
    Vector VecAns(b.dim());
    for (int i = 0; i < b.dim(); i++)
        VecAns[i] = b[i] / a;
    return VecAns;
}
const Vector i(2, { 1,0 });
const Vector j(0, 1);
const Vector i3(1, 0, 0);
const Vector j3(0, 1, 0);
const Vector k3(0, 0, 1);
Vector operator^(Vector a, Vector b)
{
    Vector Vec1(3), Vec2(3), VecAns(3);
    if (a.dim() == 2)
        Vec1[0] = a[0], Vec1[1] = a[1], Vec1[2] = 0;
    else if (a.dim() == 3)Vec1 = a;
    else {
        throw R"(illegal vector cross product operation)";
    }
    if (b.dim() == 2)
        Vec2[0] = b[0], Vec2[1] = b[1], Vec2[2] = 0;
    else if (b.dim() == 3)Vec2 = b;
    else {
        throw R"(illegal vector cross product operation)";
    }
    /*
    * Vec1 = xi + yj + zk
    * Vec2 = ui + vj + wk
    *          | i  j  k |
    * VecAns = | x  y  z |
    *          | u  v  w |
    */
    VecAns = (Vec1[1] * Vec2[2] - Vec1[2] * Vec2[1]) * i3 - (Vec1[0] * Vec2[2] - Vec1[2] * Vec2[0]) * j3 + (Vec1[0] * Vec2[1] - Vec1[1] * Vec2[0]) * k3;
    return VecAns;
}
Vector Cross(Vector a, Vector b)
{
    return a ^ b;
}

Vector Rotate(Vector Vec, long double alpha)
{
    if (Vec.dim() != 2)
    {
        throw"illegal vector rotating operation";
        return Vector(0);
    }
    Matrix MatAns = RotateMat(alpha) * ColVec(Vec);
    Vector VecAns(MatAns.at(0,0),MatAns.at(1,0));
    return VecAns;
}

long double Vector::direction()
{
    if (this->_dim != 2)
    {
        throw"illegal function call";
        return 0;
    }
    long double ans = acos(((*this) * i) / (this->mag()));
    return (this->_vec[1] >= 0) ? ans : -ans;
}

Vector Vector::UnitVec()
{
    Vector VecAns(*this);
    long double mag = this->mag();
    for (auto& i : VecAns._vec)
    {
        i /= mag;
    }
    return VecAns;
}

